<?php
namespace app\Listener;

use Exception;
use Swostar\Event\Listener;
use Swoole\Coroutine\Http\Client;
use Swostar\Server\WebSocket\Connections;
use Swostar\Server\WebSocket\WebSocketServer;

class WsMessageBeforeListener extends Listener
{
    protected $name = 'ws.message.before';

    public function run(WebSocketServer $webSocketServer = null, $swooleServer = null, $frame = null)
    {
        // 消息格式为：
        // {
        //     "method" : 群聊：chatGroup  单聊：chatSingle , 
        //     "msg" : '消息内容'
        // }

        echo "<pre>";
        print_r($frame->data);
        echo "</pre>";
        echo PHP_EOL;
        
        $data = json_decode($frame->data, true);

  

        if (!method_exists($this, $data['method'])) {
            throw new Exception("方法不存在", 500);
        }

        $this->{$data['method']}($webSocketServer, $data, $frame->fd, $swooleServer);
    }

    /**
     * 群聊，创建协程，通知路由转发至其他服务器
     * @param WebSocketServer|null $webSocketServer 
     * @param mixed|null $data 用户发送的数据
     * @param mixed|null $fd 发送人标识
     * @return void 
     */
    private function chatGroup(WebSocketServer $webSocketServer = null, $data = null, $fd = null)
    {
        $config = app('config')->get('server.routeServer');

        // 创建协程客户端
        $cli = new Client($config['ip'], $config['port']);

        if ($cli->upgrade('/')) {
            $cli->push(json_encode([
                'method' => 'chatGroup',
                'msg' => $data['msg'],
            ]));
        }
    }

    /**
     * 接受路由广播，用户发送群聊消息
     * 路由转发消息到不同imserver，各server根据存储的fd，发送给对应用户
     * @param WebSocketServer $webSocketServer 
     * @param mixed $data 
     * @param mixed $fd 
     * @return void 
     */
    private function acceptRouteBroadcast(WebSocketServer $webSocketServer, $data, $fd)
    {
        // 接收到路由发送的广播信息，群聊通知

        // 发送消息
        $webSocketServer->sendGroup($data['groupId'] ?? null, $data['msg']);
    }


    /**
     * 转发用户私聊消息
     * 获取用户私聊对象id，查找对方所在服务器，进行转发
     * @param WebSocketServer $webSocketServer 
     * @param mixed $data 
     * @param mixed $fd 
     * @return void 
     */
    private function chatSignle(WebSocketServer $webSocketServer, $data, $fd, $swooleServer)
    {
        // 获取私聊的用户id
        $clientId = $data['clientId'];

        // 获取到用户对应信息  获取用户对应imserver
        $clientIMServerInfo = $webSocketServer->getRedis()->hGet(app('config')->get('server.routeServer.jwt.key'), $clientId);
        $clientIMServerInfo = json_decode($clientIMServerInfo, true);
        
        // 对方所在imserver
        $url = $clientIMServerInfo['serverUrl'];

        // 获取发送方的token 
        $request = Connections::get($fd)['request'];
        $token = $request->header['sec-websocket-protocol'];

        if (!isset($clientIMServerInfo['fd'])) {
            echo '对方未登录' . PHP_EOL;
            return;
        }

        // 发送的数据
        $data = [
            'method' => 'acceptChatSignle',
            'msg' => $data['msg'],
            'fd' => $clientIMServerInfo['fd'] // 对方标识fd
        ];

        // 判断服务器是否为当前服务器，若是，则直接发送消息给对方
        $config = app('config')->get('server');
     
        // if ($url == $config['localhost'] . ':' . $config['websocket']['port']) {
        //     $swooleServer->push($clientIMServerInfo['fd'], 
        //         json_encode(['msg' => $data['msg']])    
        //     );
        // }

        // 发送
        list($ip, $port) = explode(':', $url);

        // 若不是当前服务器，则通过协程转发到对应服务器
        $webSocketServer->send('127.0.0.1', 9999, [
            'method' => 'acceptChatSignle',
            'msg' => $data['msg'],
            'fd' => $clientIMServerInfo['fd'] // 对方标识fd
        ], [
            'sec-websocket-protocol' => $token
        ]);
    }

    /**
     * 接受转发的私聊信息，
     * @param WebSocketServer $webSocketServer 
     * @param mixed $data 
     * @param mixed $fd 
     * @param mixed $swooleServer 
     * @return void 
     */
    private function acceptChatSignle(WebSocketServer $webSocketServer, $data, $fd, $swooleServer)
    {
        $swooleServer->push($data['fd'], json_encode(['msg' => $data['msg']]));
    }


}
